//
//  RequestService.swift
//  TuneMate
//
//  Created by 丸子 on 2023/11/30.
//


import Foundation
import Alamofire
//import CommonCrypto
import CommonCrypto
import CryptoKit

let apiHost = "https://ai.api.gzwstwh.cn"

//let apiHost = "http://test.zhugeai.letonglive.com"

let app_secret = "fYGNR74WNYDmQ7Wm"
let system_id = "nideai"
 
// 定义请求成功回调类型
typealias ReqSuccBlock<T: Decodable> = (T?) -> Void
// 定义请求失败回调类型
typealias ReqFailBlock = (RequestError) -> Void
// 定义请求错误结构体
struct RequestError {
    let code: RequestErrorCode // 错误码
    var serverCode: Int? = 0 // 服务器错误码
    let msg: String? // 错误信息
    var afError: AFError? = nil // AFError 对象
}
// 定义通用响应结构体
struct CommonResponse<T:Decodable>: Decodable {
    let code: Int // 响应码
    let key: String // 响应 key
    let msg: String // 响应信息
    let result: T? // 响应数据
}
// 定义空参数结构体
struct NilArgs: Codable {}
// 定义服务器响应码结构体
struct ReqServerCode : HandyJSON {
    var code: Int = 0 // 响应码
    var key: String? // 响应 key
    var msg: String? // 响应信息
}
// 定义请求错误码枚举
enum RequestErrorCode {
    case DECODE_JSON_ERROR // JSON 解码错误
    case DECODE_ERROR // 解码错误
    case SERVER_ERROR // 服务器错误
    case NETWORK_ERROR // 网络错误
}

class RequestService {
    static let TAG = "RequestService"
    static let instance = RequestService() // 单例对象
    var session : Session // 网络会话对象
    var isRequest:Bool = false
    
    private init() { // 私有初始化函数，防止外部创建对象
        let conf: URLSessionConfiguration = URLSessionConfiguration.af.default
        conf.timeoutIntervalForRequest = 40 // 设置超时时间为 15 秒
        session = Session(configuration: conf, interceptor: CommonInterceptor()) // 创建会话对象并设置拦截器
    }
    
}
extension RequestService {
    // 定义 statRequest 函数，用于统计请求信息
    func statRequest(_ resp: DataResponse<Data, AFError>) {
        let url = resp.request?.url // 请求 URL
        let duration = resp.metrics?.taskInterval.duration ?? 0 // 请求耗时
        XLog.d(RequestService.TAG, "\n\n======================================== start ======================================")
        XLog.d(RequestService.TAG, resp.request?.method?.rawValue ,"URL:", url, "Time:", String(format: "%.2f", duration))
        XLog.d(RequestService.TAG, "header: ", resp.request?.headers.dictionary.jsonString())
        if let body = resp.request?.httpBody?.string(encoding: .utf8){
            XLog.d(RequestService.TAG, "body: ", body)
        }
        // 处理响应结果
        switch resp.result {
        case .success(let data):
            let JSON = try? JSON(data: data, options: .mutableContainers)
            let JSONStr = JSON?.rawString(options: .fragmentsAllowed)
            XLog.d(RequestService.TAG, "response: \n\n", JSONStr)
            guard let model = ReqServerCode.deserialize(from: JSONStr) else { return }
            if model.code != 200{
                NDProgressHUD.hide()
                GlobalRx.requestErrSubject.onNext(model)
            }
        case .failure(let error):
            XLog.d(RequestService.TAG, "response: ", error.localizedDescription)
            NDProgressHUD.showError(title: "tips", subtitle: error.localizedDescription)
        }
        //        TLog.d(RequestService.TAG, "response_headers: ", resp.response?.headers.dictionary.jsonString())
        XLog.d(RequestService.TAG, "========================================= end =====================================")
    }
    
    func generateHash(data: [String: Any]) -> String {
        var result = ""
        // Sort keys
        let sortedKeys = data.keys.sorted()
        // Concatenate key-value pairs
        for key in sortedKeys {
            if let value = data[key] as? String {
                result += key + value
            }
        }
        // Append appSecret
        result = app_secret + result + app_secret
        if #available(iOS 13.0, *) {
            // Generate MD5 hash
            let hash = Insecure.MD5.hash(data: result.data(using: .utf8) ?? Data())
            // Convert hash to hex string
            let hashString = hash.map { String(format: "%02hhx", $0) }.joined()
            return hashString.uppercased()
        }else {
            return MD5(string: result).uppercased()
        }
    }
    func MD5(string: String) -> String {
        let length = Int(CC_MD5_DIGEST_LENGTH)
        let messageData = string.data(using:.utf8)!
        var digestData = Data(count: length)
        _ = digestData.withUnsafeMutableBytes { digestBytes in
            messageData.withUnsafeBytes { messageBytes in
                CC_MD5(messageBytes.baseAddress, CC_LONG(messageData.count), digestBytes.bindMemory(to: UInt8.self).baseAddress)
            }
        }
        return digestData.map { String(format: "%02hhx", $0) }.joined()
    }
    
    
}
class CommonInterceptor: RequestInterceptor {
    //    var retryCount = 0
    //    func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
    //        if self.retryCount < 3 {
    //            completion(.retryWithDelay(2))
    //            retryCount += 1
    //        }else{
    //            completion(.doNotRetry)
    //        }
    //    }
    
    func commonHeader() -> [String: String] {
        if let model = Appearance.shared.accoutModel {
            return ["channel_code": "ios",
                    "oaid": Device.IDFA,
                    "version_code": Device.VERSION_NAME,
                    "system_id":system_id,
                    "authorization":"Bearer \(model.token ?? "")"
            ]
        }else {
            return ["channel_code": "ios",
                    "oaid": Device.IDFA,
                    "version_code": Device.VERSION_NAME,
                    "system_id":system_id
            ]
        }
    }
    
    func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Swift.Error>) -> Void) {
        var req = urlRequest
        for (key, value) in commonHeader() {
            if let url = req.url?.absoluteString, !url.contains("microsoft") {
                req.addValue(value, forHTTPHeaderField: key)
            }
        }
        //        req.headers.add(.authorization(bearerToken: AccountService.instance.currentAccount?.token ?? ""))
        completion(.success(req))
    }
}
